/*
 * zachutil_Char.cpp
 *
 *  Created on: 2011-9-24
 *      Author: 胡剑青
 */

#include "util.h"
#include <fstream>

namespace zach
{
namespace util
{
UTF8Reader::UTF8Reader()
{
	_in = NULL;
	_position.col = -1;
	_position.row = -1;
}

UTF8Reader::~UTF8Reader()
{
	if ( _in != NULL)
	{
		delete _in;
	}
}

TextPosition UTF8Reader::position() const
{
	if ( _in == NULL)
	{
		throw Fault( "UTF8Reader::charPos no stream available" );
	}

	return _position;
}

Char UTF8Reader::lastRead() const
{
	if ( _in == NULL)
	{
		throw Fault( "UTF8Reader::u32char no stream available" );
	}

	if ( _position.row <= 0 || _position.col <= 0 ) {
		throw Fault( "UTF8Reader::u32char char not read yet" );
	}

	return _present;
}

bool UTF8Reader::isEnd() const
{
	if ( _in == NULL)
	{
		throw Fault( "UTF8Reader::u32char no stream available" );
	}
	return _in->eof();
}

void UTF8Reader::init( std::string path )
{
	if ( _in != NULL)
	{
		delete _in;
	}
	_in = new std::ifstream( path.c_str(), std::ios::in | std::ios::binary );
	_position.col = 0;
	_position.row = 0;
	_present = ( Char ) '\n';
}

//辅助函数：转换首char为/[1]{n}0[01]{(7-n)}/11...1(n个)0xx...x((7-n)个)的非ASCII字符
static Char Cast( std::istream* in, char first, int n )
{
	Char ret = 0;
	int rest = n - 1; //剩余字节数

	//首字节去头位移拼入
	ret += ( ( first & ( 0x000000FF >> ( n + 1 ) ) ) << ( 6 * rest ) );

	//对于每个后续字节
	while ( rest > 0 ) {
		rest--;
		//读入
		char next;
		in->get( next );
		//检查
		if ( ( ( unsigned char ) next ) > 0xBF || ( ( unsigned char ) next ) < 0x80 ) {
			throw Fault( "UTF8Reader::readChar() invalid char" );
		}
		//去头位移拼入
		ret += ( ( next & 0x0000003F ) << ( 6 * rest ) );
	}

	return ret;
}

void UTF8Reader::readChar()
{
	//是否换行
	bool nl = _present == ( Char ) '\n';

	char next = 0;

	//读第一个char
	_in->get( next );

	//遇到文件结尾直接返回
	if ( _in->eof() ) {
		return;
	}

	//其他错误崩溃
	if ( !( _in->good()) ) {
		throw Fault( "UTF8Reader::readChar() stream error" );
	}

	if ( next == '\r' ) {
		//行尾
		_in->get( next );
		if ( next != '\n' ) {
			throw Fault( "UTF8Reader::readChar() invalid new line mark" );
		}
		else {
			_present = '\n';
		}
	}
	else {
		//计算字节数
		int cb = 0;
		unsigned char rest = next;
		while ( rest > 0x80 ) {
			cb++;
			rest <<= 1;
		}

		//处理当前字符
		if ( cb == 0 ) {
			//单字节兼容ASCII
			_present = ( Char ) next;
		}
		else if ( cb >= 2 && cb <= 6 ) {
			//多字节固定格式
			_present = Cast( _in, next, cb );
		}
		else {
			//非UCS4
			throw Fault( "UTF8Reader::readChar() invalid char format" );
		}
	}

	if ( nl ) {
		_position.row++;
		_position.col = 1;
	}
	else {
		_position.col++;
	}
}

}
}
